﻿using System;
using System.Web;
using log4net;
using Machinery.Providers;
using Moq;
using NHibernate;
using NHibernate.Cfg;
using Ninject;
using Ninject.Activation.Providers;
using Ninject.Infrastructure;
using Ninject.Moq;
using Ninject.Planning.Bindings;

namespace Machinery
{
    public class MachineryKernel : StandardKernel
    {
        public MachineryKernel()
        {
            BindNHibernate();

            Bind<ILog>().ToMethod(method => LogManager.GetLogger("Machinery.Errors"));

        }

        /// <summary>
        /// Bind or rebind NHibernate Configuration, Session Factory and Session
        /// </summary>
        public virtual void BindNHibernate()
        {
            // Using Rebind instead of bind to allow this method to be called a second time by tests.
            Rebind<Configuration>().ToProvider<NHibernateConfigurationProvider>().InSingletonScope();
            Rebind<ISessionFactory>().ToMethod(ctx => this.Get<Configuration>().BuildSessionFactory()).InSingletonScope();
            Rebind<ISession>().ToMethod(method => this.Get<ISessionFactory>().OpenSession())
                .InScope(HttpContext.Current == null ? StandardScopeCallbacks.Thread : StandardScopeCallbacks.Request);
        }

        protected override bool HandleMissingBinding(Type serviceType)
        {
            if (base.HandleMissingBinding(serviceType))
                return true;

            // Try to get class by removing initial I from the Interface name, 
            // and ".Interfaces" from the namespace.
            // I.e. ConventionKernel will try to autobind MyEcommerceStore.Cogs.ICreditCardCog
            // to MyEcommerceStore.Cogs.CreditCardCog
            var serviceNameWithoutI = serviceType.Name.IndexOf("I") == 0 ? serviceType.Name.Substring(1) : serviceType.Name;
            var potentialClassName = String.Format("{0}.{1}", serviceType.Namespace.Replace(".Interfaces", ""), serviceNameWithoutI);
            var type = serviceType.Module.GetType(potentialClassName);
            if (type == null || type.IsInterface || !serviceType.IsAssignableFrom(type))
                return false;

            var binding = new Binding(serviceType)
                              {
                                  ProviderCallback = StandardProvider.GetCreationCallback(type),
                                  Target = BindingTarget.Type
                              };
            // Use request scope or transient scope depedning on whether or not it's available.
            binding.ScopeCallback = HttpContext.Current == null ? StandardScopeCallbacks.Thread : StandardScopeCallbacks.Request;

            AddBinding(binding);
            return true;

        }


    }
}